package com.spzx.product.service.impl;

import com.spzx.common.core.utils.StringUtils;
import com.spzx.product.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 本地锁测试
     *    单台节点没有问题
     *    集群模式会出现数据不一致
     */
//   @Override
//   public synchronized void testLock() {
//      // 查询Redis中的num值
//      String value = this.stringRedisTemplate.opsForValue().get("num");
//      // 没有该值return
//      if (StringUtils.isBlank(value)){
//         return ;
//      }
//      // 有值就转成int
//      int num = Integer.parseInt(value);
//      // 把Redis中的num值+1
//      this.stringRedisTemplate.opsForValue().set("num", String.valueOf(++num));
//   }

    /**
     * 分布式锁测试第一版
     *    将分布式锁添加到Redis中，使用Redis中的setnx命令添加分布式锁，在StringRedisTemplate中对应的方法是：setIfAbsent方法
     *    存在的问题：
     *       当业务逻辑执行出现异常时会出现死锁现象
     */
//   @Override
//   public void testLock(String port) {
//      //获取Redis中的分布式锁
//      Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent("lock", "helloRedis");
//      if(flag){
//         System.out.println("获取分布式锁成功");
//         // 查询Redis中的num值
//         String value = this.stringRedisTemplate.opsForValue().get("num");
//         // 没有该值return
//         if (StringUtils.isBlank(value)){
//            return ;
//         }
//
//         //如果请求的是9205这台机器则出异常
//         if("9205".equals(port)){
//            //设置数学异常
//            System.out.println(1/0);
//         }
//
//         // 有值就转成int
//         int num = Integer.parseInt(value);
//         // 把Redis中的num值+1
//         this.stringRedisTemplate.opsForValue().set("num", String.valueOf(++num));
//
//         //执行完业务逻辑，一定要释放锁
//         stringRedisTemplate.delete("lock");
//
//      }else{
//         System.err.println("获取分布式锁失败：重试");
//          try {
//               //睡1秒再重试
//              Thread.sleep(1000);
//          } catch (InterruptedException e) {
//              throw new RuntimeException(e);
//          }
//          //重试，再次调用testLock方法尝试获取分布式锁
//          testLock(port);
//      }
//
//   }


    /**
     * 分布式锁测试第二版
     *  使用try catch finally解决死锁问题
     */
    @Override
    public void testLock(String port) {
        //获取Redis中的分布式锁
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent("lock", "helloRedis");
        if(flag){
            try {
                System.out.println("获取分布式锁成功");
                // 查询Redis中的num值
                String value = this.stringRedisTemplate.opsForValue().get("num");
                // 没有该值return
                if (StringUtils.isBlank(value)){
                    return ;
                }

                //如果请求的是9205这台机器则出异常
//               if("9215".equals(port)){
//                   //设置数学异常
//                   System.out.println(1/0);
//               }

                // 有值就转成int
                int num = Integer.parseInt(value);
                // 把Redis中的num值+1
                this.stringRedisTemplate.opsForValue().set("num", String.valueOf(++num));


            } catch (NumberFormatException e) {
                System.err.println("出错啦："+e.getMessage());
            } finally {
                //执行完业务逻辑不管是否出现异常，一定要释放锁
                stringRedisTemplate.delete("lock");
            }

        }else{
            System.err.println("获取分布式锁失败：重试");
            try {
                //睡1秒再重试
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //重试，再次调用testLock方法尝试获取分布式锁
            testLock(port);
        }

    }

}